package cn.dslcode.security.config.oauth2;

import cn.dslcode.common.core.string.StringUtil;
import cn.dslcode.common.web.response.ResponseCode;
import cn.dslcode.security.common.AuthenticationFailureResult;
import cn.dslcode.security.common.CaptchaAuthenticationException;
import cn.dslcode.security.common.OAuth2ResponseCode;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

/**
 * @author dongsilin
 * @version 2018/4/8.
 *          图片验证码Filter
 */
@Slf4j
@Data
public final class CustomWebAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    /**
     * 验证码字段名称
     */
    private String captchaCodeParameterName;

    /**
     * 建立构造器，排除循环依赖
     * @param authenticationManager
     */
    public CustomWebAuthenticationFilter(AuthenticationManager authenticationManager, String loginFormUri, String captchaCodeParameterName) {
        super();
        setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(loginFormUri, RequestMethod.POST.name()));
        setAuthenticationManager(authenticationManager);
        setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(){
            @Override
            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                ResponseCode errorInfo = null;
                if (authException instanceof CaptchaAuthenticationException) {
                    errorInfo = OAuth2ResponseCode.valueOf(authException.getMessage());
                } else if (authException instanceof UsernameNotFoundException) {
                    errorInfo = OAuth2ResponseCode.username_not_exists;
                } else if (authException instanceof BadCredentialsException) {
                    errorInfo = OAuth2ResponseCode.password_error;
                }
                request.getSession().setAttribute("authError", new AuthenticationFailureResult(request.getParameter("username"), request.getParameter("password"), errorInfo));
                response.sendRedirect(loginFormUri);
            }
        });
        this.captchaCodeParameterName = captchaCodeParameterName;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            if (StringUtil.eq(parameterNames.nextElement(), this.captchaCodeParameterName)) {
                String captchaCode = request.getParameter(this.captchaCodeParameterName);
                if (StringUtil.isEmpty(captchaCode)) {
                    throw new CaptchaAuthenticationException(OAuth2ResponseCode.captcha_code_empty.getName());
                }else if (StringUtil.ne(captchaCode, "1234")) {
                    throw new CaptchaAuthenticationException(OAuth2ResponseCode.captcha_code_error.getName());
                }
                break;
            }
        }
        return super.attemptAuthentication(request, response);
    }

}